/*
*  Copyright (c) 2001 Sun Microsystems, Inc.  All rights
*  reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*  1. Redistributions of source code must retain the above copyright
*  notice, this list of conditions and the following disclaimer.
*
*  2. Redistributions in binary form must reproduce the above copyright
*  notice, this list of conditions and the following discalimer in
*  the documentation and/or other materials provided with the
*  distribution.
*
*  3. The end-user documentation included with the redistribution,
*  if any, must include the following acknowledgment:
*  "This product includes software developed by the
*  Sun Microsystems, Inc. for Project JXTA."
*  Alternately, this acknowledgment may appear in the software itself,
*  if and wherever such third-party acknowledgments normally appear.
*
*  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA"
*  must not be used to endorse or promote products derived from this
*  software without prior written permission. For written
*  permission, please contact Project JXTA at http://www.jxta.org.
*
*  5. Products derived from this software may not be called "JXTA",
*  nor may "JXTA" appear in their name, without prior written
*  permission of Sun.
*
*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
*  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*  DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
*  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
*  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
*  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
*  SUCH DAMAGE.
*  ====================================================================
*
*  This software consists of voluntary contributions made by many
*  individuals on behalf of Project JXTA.  For more
*  information on Project JXTA, please see
*  <http://www.jxta.org/>.
*
*  This license is based on the BSD license adopted by the Apache Foundation.
*
*  $Id: FilterChain.java,v 1.5 2007/01/26 21:54:25 bondolo Exp $
*/

package net.jxta.myjxta.dialog;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import java.util.logging.Level;
import net.jxta.logging.Logging;
import java.util.logging.Logger;

/**
 * Holds a {@link List} of filters for removing and modifying the text of <code>DialogMessage</code>s.
 */
public class FilterChain {

    private static final Object LOCK = new Object();
    private List<DialogFilter> filters = null;
    static final Logger LOG = Logger.getLogger(FilterChain.class.getName());


    /**
     * Returns a clone of the current list of {@link DialogFilter}s
     * 
     * @return A clone of the current list of {@link DialogFilter}s
     */
    public List getFilters() {
        return this.filters != null ? new ArrayList<DialogFilter>(this.filters) : Collections.EMPTY_LIST;
    }

    /**
     * Adds a <code>DialogFilter</code> to current list of filters
     * If a <code>DialogFilter</code> of the same Class is already in the list, then the new filter is replaces 
     * the existing filter, otherwise the new filter is added to the end of the list.
     * 
     * @param filter The filter to be added to the current list of {@link DialogFilter}s.
     */
    public synchronized void addFilter(DialogFilter filter) {
        if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
            LOG.fine("Begin addFilter(DialogFilter)");
            LOG.fine("filter.getClass() = " + filter.getClass());
        }

        if (filter == null) {
            return;
        }
        
        if (this.filters == null) {
            this.filters = new ArrayList<DialogFilter>();
        }

        int index = -1;

        if ((index = filters.indexOf(filter)) > -1) {
            this.filters.set(index, filter);
        } else {
            this.filters.add(filter);
        }

        LOG.fine("End   addFilter(DialogFilter)");
    }

    /**
     * Adds a List of <code>DialogFilter</code>s to the end of the current list.
     * 
     * @param filters The list of {@link DialogFilter}s to be added to the current list.
     */
    public void addFilters(List filters) {
        for (Iterator f = filters.iterator(); f.hasNext(); ) {
            addFilter((DialogFilter)f.next());
        }
    }

    /**
     * Removes a <code>DialogFilter</code> from the current list.
     * 
     * @param filterClass the class of the filter to be removed.  Must subclass {@link DialogFilter}.
     * @return The {@link DialogFilter} that was removed from the list.
     */
    public DialogFilter removeFilter(Class filterClass) {
        if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
            LOG.fine("Begin removeFilter(Class)");
            LOG.fine("filterClass = " + filterClass);
        }

        DialogFilter df = null;
        if (DialogFilter.class.isAssignableFrom(filterClass)) {
            try {
                df = (DialogFilter)filterClass.newInstance();
            } catch (IllegalAccessException e) {
                // should never happen
                LOG.log(Level.SEVERE, "Caught unexpected Exception", e);
                return null;
            } catch (InstantiationException e) {
                // should never happen
                LOG.log(Level.SEVERE, "Caught unexpected Exception", e);
                return null;
            }
        }
        int i = (this.filters != null && filterClass != null) ? this.filters.indexOf(df) : -1;

        if (i > -1) {
            assert this.filters != null;
            df = this.filters.get(i);
            df.setValid(false);
        }

        LOG.fine("End   removeFilter(Class)");

        return df;
    }

    /**
     * Removes a List of <code>DialogFilter</code>s from the current list.
     * 
     * @param filters The list of {@link DialogFilter}s to be removed from the current list.
     * @return The <code>List</code> of <code>DialogFilter</code>s that were actually removed.
     */
    public List<DialogFilter> removeFilters(List filters) {
        List<DialogFilter> l = new ArrayList<DialogFilter>();
        DialogFilter df = null;

        for (Iterator f = filters.iterator(); f.hasNext(); ) {
            df = removeFilter(f.next().getClass());

            if (df != null) {
                l.add(df);
            }
        }

        return l;
    }

    /**
     * Removes all <code>DialogFilter</code>s from the current list.
     * 
     * @return The <code>List</code> of <code>DialogFilter</code>s that were removed.
     */
    public List<DialogFilter> clearFilters() {
        List<DialogFilter> f = null;

        synchronized (LOCK) {
            if (this.filters != null) {
                Collections.copy(this.filters, f);

                this.filters.clear();
                this.filters = null;
            }
        }

        return f;
    }
}

